package com.iams.manage.service.impl;



import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.iams.common.utils.SearchContextHolder;
import com.iams.common.utils.SecurityUtils;
import com.iams.elasticsearch.domain.ElasticsearchArchive;
import com.iams.manage.mapper.UserPostMapper;
import com.iams.manage.service.IElasticsearchArchiveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

//import static com.iams.framework.datasource.DynamicDataSourceContextHolder.log;

@Service
public class ElasticsearchArchiveServiceImpl implements IElasticsearchArchiveService {

    private final ElasticsearchClient client;

    private static final Map<String, List<String>> POST_SECURITY_RULES = Map.of(
            "user", List.of("Unclassified"),
            "auditor", List.of("Unclassified", "Internal", "Confidential"),
            "director", List.of("Unclassified", "Internal", "Confidential", "Secret", "TopSecret")
    );

    @Autowired
    public ElasticsearchArchiveServiceImpl(ElasticsearchClient client) {
        this.client = client;
    }

    @Autowired
    public UserPostMapper userPostMapper;

    @Override
    public List<ElasticsearchArchive> CombineSearch(Map<String, String> combineParams) {
        List<ElasticsearchArchive> list = new ArrayList<>();
        int restrictedCount = 0;

        // 1. 创建两个独立的Builder
        BoolQuery.Builder totalQueryBuilder = new BoolQuery.Builder(); // 用于总数查询
        BoolQuery.Builder filteredQueryBuilder = new BoolQuery.Builder(); // 用于实际数据查询

        // 收集所有查询字段，用于高亮
        Set<String> queryFields = new HashSet<>();

        // 2. 构建基础查询条件（两个Builder都需要）
        buildBaseQueryConditions(totalQueryBuilder, combineParams, queryFields);
        buildBaseQueryConditions(filteredQueryBuilder, combineParams, queryFields);

        try {
            // 3. 执行总数查询（不带权限过滤）
            long totalHits = executeCountQuery(totalQueryBuilder);

            // 4. 添加权限过滤到第二个Builder
            addSecurityFilter(filteredQueryBuilder, getCurrentUserPostCodes());

            // 5. 执行实际数据查询（带权限过滤）
            SearchResponse<ElasticsearchArchive> response = executeDataQuery(filteredQueryBuilder, queryFields);

            // 6. 计算并保存无权限记录数
            restrictedCount = (int)(totalHits - response.hits().hits().size());
            SearchContextHolder.setRestrictedCount(restrictedCount);

            // 7. 处理返回结果
            processSearchResults(response, list);

        } catch (IOException e) {
            //log.error("执行 Elasticsearch 查询失败", e);
            throw new RuntimeException("执行 Elasticsearch 查询失败", e);
        }

        return list;
    }

    /**
     * 构建基础查询条件（公共部分）
     */
    private void buildBaseQueryConditions(BoolQuery.Builder builder,
                                          Map<String, String> params,
                                          Set<String> queryFields) {
        // 处理主条件1
        if (params.containsKey("MainType") && params.containsKey("MainTypeValue")) {
            String logic = params.getOrDefault("MainTypeLogic", "AND");
            String field = params.get("MainType");
            addCondition(builder, logic, field, params.get("MainTypeValue"));
            queryFields.add(field);
        }

        // 处理主条件2
        if (params.containsKey("secondMainType") && params.containsKey("secondMainTypeValue")) {
            String logic = params.getOrDefault("secondMainTypeLogic", "AND");
            String field = params.get("secondMainType");
            addCondition(builder, logic, field, params.get("secondMainTypeValue"));
            queryFields.add(field);
        }

        // 处理动态条件
        int index = 0;
        int maxEmptyChecks = 10;
        int emptyCount = 0;

        while (emptyCount < maxEmptyChecks) {
            String fieldKey = "dynamicField" + index;
            String valueKey = "dynamicValue" + index;
            String logicKey = "dynamicLogic" + index;
            String field = params.getOrDefault(fieldKey, "");
            String value = params.getOrDefault(valueKey, "");
            String logic = params.getOrDefault(logicKey, "AND");

            if (!field.isEmpty() && !value.isEmpty()) {
                addCondition(builder, logic, field, value);
                queryFields.add(field);
                emptyCount = 0;
            } else {
                emptyCount++;
            }
            index++;
        }
    }

    /**
     * 执行计数查询
     */
    private long executeCountQuery(BoolQuery.Builder builder) throws IOException {
        SearchResponse<ElasticsearchArchive> response = client.search(s -> s
                        .index("archives")
                        .query(q -> q.bool(builder.build()))
                        .size(0),
                ElasticsearchArchive.class);
        return response.hits().total().value();
    }

    /**
     * 执行数据查询（带高亮）
     */
    private SearchResponse<ElasticsearchArchive> executeDataQuery(
            BoolQuery.Builder builder,
            Set<String> queryFields) throws IOException {

        // 构建高亮配置
        Map<String, HighlightField> highlightFields = buildHighlightFields(queryFields);

        return client.search(s -> s
                        .index("archives")
                        .query(q -> q.bool(builder.build()))
                        .highlight(h -> h
                                .fields(highlightFields)
                                .requireFieldMatch(false)
                        ),
                ElasticsearchArchive.class);
    }

    /**
     * 构建高亮字段配置
     */
    private Map<String, HighlightField> buildHighlightFields(Set<String> queryFields) {
        Map<String, HighlightField> highlightFields = new HashMap<>();
        for (String field : queryFields) {
            highlightFields.put(field, HighlightField.of(hf -> hf
                    .preTags("<span class='highlight'>")
                    .postTags("</span>")
            ));
            // 处理嵌套字段
            if (field.startsWith("documents.")) {
                String nestedField = field.substring("documents.".length());
                highlightFields.put("documents." + nestedField, HighlightField.of(hf -> hf
                        .preTags("<span class='highlight'>")
                        .postTags("</span>")
                ));
            }
        }
        return highlightFields;
    }

    /**
     * 处理搜索结果
     */
    private void processSearchResults(SearchResponse<ElasticsearchArchive> response,
                                      List<ElasticsearchArchive> resultList) {
        for (Hit<ElasticsearchArchive> hit : response.hits().hits()) {
            if (hit.source() != null) {
                ElasticsearchArchive archive = hit.source();
                // 设置高亮结果
                if (hit.highlight() != null) {
                    Map<String, List<String>> highlights = new HashMap<>();
                    for (Map.Entry<String, List<String>> entry : hit.highlight().entrySet()) {
                        String key = entry.getKey();
                        if (key.startsWith("documents.")) {
                            String nestedField = key.substring("documents.".length());
                            highlights.put("documents." + nestedField, entry.getValue());
                        } else {
                            highlights.put(key, entry.getValue());
                        }
                    }
                    archive.setHighlights(highlights);
                }
                resultList.add(archive);
            }
        }
    }

    // ============== 以下方法保持不变 ==============

    private void addSecurityFilter(BoolQuery.Builder builder, List<String> userPosts) {
        if (userPosts == null || userPosts.isEmpty()) {
            return;
        }

        List<String> allowedLevels = userPosts.stream()
                .flatMap(post -> POST_SECURITY_RULES.getOrDefault(post, Collections.emptyList()).stream())
                .distinct()
                .collect(Collectors.toList());

        if (!allowedLevels.isEmpty()) {
            builder.filter(f -> f.terms(t -> t
                    .field("secretLevel")
                    .terms(terms -> terms.value(allowedLevels.stream()
                            .map(FieldValue::of)
                            .collect(Collectors.toList()))
                    )));
        }
    }

    private boolean isAdminUser(Long userId) {
        return userId == 1L;
    }

    private List<String> getCurrentUserPostCodes() {
        try {
            Long userId = SecurityUtils.getLoginUser().getUserId();
            if (isAdminUser(userId)) {
                return Collections.emptyList();
            }

            Page<String> page = PageHelper.startPage(1, Integer.MAX_VALUE, false)
                    .doSelectPage(() -> userPostMapper.selectPostCodesByUserId(userId));

            //log.debug("用户{}岗位数据: {}", userId, page.getResult());
            return page.getResult();

        } catch (Exception e) {
            //log.error("获取岗位失败", e);
            return Collections.emptyList();
        }
    }

    private void addCondition(BoolQuery.Builder builder, String logic, String field, String value) {
        if (field == null || value == null || field.isEmpty() || value.isEmpty()) return;

        final Query query;
        if (field.startsWith("documents.")) {
            String nestedField = field.substring("documents.".length());
            query = Query.of(q -> q
                    .nested(n -> n
                            .path("documents")
                            .query(Query.of(q2 -> q2
                                    .bool(b -> b
                                            .must(Query.of(q3 -> q3
                                                    .match(m -> m
                                                            .field("documents." + nestedField)
                                                            .query(value)
                                                    )
                                            ))
                                    )
                            ))));
        } else {
            if (field.equals("mysqlDanghao")) {
                query = Query.of(q -> q.term(t -> t.field(field).value(value)));
            } else {
                query = Query.of(q -> q.match(m -> m.field(field).query(value)));
            }
        }

        switch (logic.toUpperCase()) {
            case "OR":
                builder.should(query);
                break;
            case "NOT":
                builder.mustNot(query);
                break;
            case "AND":
            default:
                builder.must(query);
                break;
        }
    }
}